﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#pragma once

#include "GbmpUiPlatform.h"
#include "ActionBase.h"
#include "Vector3d.h"
#include "WeakPtr.h"
#include "IUiView.h"
namespace gcmp
{

    class IUserTransaction;

    class GbmpPasteAction : public ActionBase
    {
    public:
        GbmpPasteAction();
        ~GbmpPasteAction();

    public:
        virtual void InitAction(IUiView* pCurrentView) override;
        virtual void OnChildActionFinished(IUiView* pCurrentView, const gcmp::ActionOutput& childActionReturnParam) override;

        //粘贴的时候会侦听子操作产生的键盘消息(目前有回车会结束子Action)
        virtual bool OnKeyDown(gcmp::IUiView* pCurrentView, int nChar) override;
        virtual bool PreviewKeyEvent() override { return true; }
        static void UpdateStoreyLevel(IDocument* pDoc, const std::vector<ElementId>& levelsTo, const std::vector<ElementId>& pastedElementIds);

    private:
        void InitSourceHelperRect(IUiView* pUiView);
        void ClearSourceHelperRect();
        void InitTargetHelperRect(IUiView* pUiView);
        void ClearTargetHelperRect();

        void InitInsertPt(IUiView* pUiView);
        void ClearInsertPt(IDocument* pDoc);

        //当粘贴过程中，鼠标移动回调函数
        void MouseMoveUpdate(IUiView* pCurrentView, const gcmp::Vector3d& pickedPt, const gcmp::Vector3d& mousePt);

        //当粘贴过程中，鼠标在移动（粘贴的目标矩形也会刷新移动）
        void PastePointUpdate(IUiView* pCurrentView, const Vector3d& pos);
        //启动获取粘贴点的Action
        void StartPickPastePointAction(IUiView* pCurrentView);
        //获取粘贴点的Action结束
        void PickPastePointActionFinished(IUiView* pCurrentView, ActionFinishStatus eFinishStatus);

    private:
        //拾取到的粘贴插入点
        Vector3d m_pickedPt;

        //TODO: IPickPointAction重构完成后，此参数删除
        //粘贴过程中，是否被用户取消:
        bool m_isUserCancelled;
        //事务（粘贴过程中需要根据条件手动启动/回滚/提交）
        OwnerPtr<IUserTransaction> m_opUserTransaction;
        //粘贴过程真正拷贝出来的对象集合
        std::vector<ElementId> m_pastedElementIds;

        //辅助定位矩形
        class HelperRect;
        OwnerPtr<HelperRect> m_opSourceHelperRect;
        OwnerPtr<HelperRect> m_opTargetHelperRect;

        //辅助插入点
        ElementId m_insertPtId;

        // 已经Picked到的点集, 按照Pick顺序存储
        std::vector<gcmp::Vector3d> m_pickedPoints;

    private:
        //粘贴时的两个辅助方框(临时对象):
        //原对象集 => 这个方框显示后保持不变
        //目标对象集 => 跟着鼠标走(相当于原对象集被复制了一份)
        class HelperRect
        {
            //屏幕像素(未来也许可通过界面设置)
            //实际的方框会比原来【对象集】四周大一点点
            enum { HELPER_RECT_GAP = 5 };

        public:
            //在视图中创建一个临时的矩形
            HelperRect(const IUiView* pUiView, GbmpPasteAction* pAction);
            ~HelperRect();

        public:
            //更新Rect中【对象集】的左下角
            void Update(const Vector3d& lbOfSet);
            void CleanupTempGraphicsShape();

            const std::vector<Vector3d>& GetCorners() const { return m_corners; }
        private:
            //目前只支持平面视图
            WeakPtr<const IUiView> m_wpUiView;
            //矩形的四个顶点
            std::vector<Vector3d> m_corners;
            double m_gap;   //矩形的四周保留的GAP
            gcmp::ElementId    m_tmpElementID;

        private:
            //HelperRect被使用的action
            GbmpPasteAction* const m_pAction;         
        };

        friend class HelperRect;
    };
}

